Bug 658767 - Drag and Drop NSEvent capture is racy
authorJohn Ralls <jralls@ceridwen.us>
Sun, 25 Sep 2011 01:19:56 +0000 (18:19 -0700)
committerJohn Ralls <jralls@ceridwen.us>
Sun, 9 Oct 2011 18:24:41 +0000 (11:24 -0700)
Create a synthetic NSMouseLeftDown to store in the GtkQuartzDragSourceInfo
rather than relying on the NSWindow's latest event being the right one (or the
right kind).

gtk/gtkdnd-quartz.c

index 6d4e709a94851e806cf6c7221d139cd01746247d..0653261c65268f66da46f2537d781e2c4a85230a 100644 (file)
@@ -1100,6 +1100,13 @@ gtk_drag_begin_idle (gpointer arg)
 
   return FALSE;
 }
+/* Fake protocol to let us call GdkNSView gdkWindow without including
+ * gdk/GdkNSView.h (which we can't because it pulls in the internal-only
+ * gdkwindow.h).
+ */
+@protocol GdkNSView
+- (GdkWindow *)gdkWindow;
+@end
 
 static GdkDragContext *
 gtk_drag_begin_internal (GtkWidget         *widget,
@@ -1110,14 +1117,47 @@ gtk_drag_begin_internal (GtkWidget         *widget,
                         GdkEvent          *event)
 {
   GtkDragSourceInfo *info;
-  GdkDragContext *context;
   GdkDevice *pointer;
-  NSWindow *nswindow;
-
-  context = gdk_drag_begin (gtk_widget_get_window (widget), NULL);
+  GdkWindow *window;
+  GdkDragContext *context = gdk_drag_begin (gtk_widget_get_window (widget),
+                                           NULL);
+  NSWindow *nswindow = get_toplevel_nswindow (widget);
+  NSPoint point = {0, 0};
+  gdouble x, y;
+  double time = (double)g_get_real_time ();
+  NSEvent *nsevent;
+  NSTimeInterval nstime;
+
+  if (event)
+    {
+      if (gdk_event_get_coords (event, &x, &y))
+        {
+          point.x = x;
+          point.y = y;
+        }
+      time = (double)gdk_event_get_time (event);
+    }
+  nstime = [[NSDate dateWithTimeIntervalSince1970: time / 1000] timeIntervalSinceReferenceDate];
+  nsevent = [NSEvent mouseEventWithType: NSLeftMouseDown
+                     location: point
+                     modifierFlags: 0
+                     timestamp: nstime
+                     windowNumber: [nswindow windowNumber]
+                     context: [nswindow graphicsContext]
+                     eventNumber: 0
+                     clickCount: 1
+                     pressure: 0.0 ];
+
+  window = [(id<GdkNSView>)[nswindow contentView] gdkWindow];
+  g_return_val_if_fail(nsevent != NULL, NULL);
+
+  context = gdk_drag_begin (window, NULL);
+  g_return_val_if_fail( context != NULL, NULL);
 
   info = gtk_drag_get_source_info (context, TRUE);
-  
+  info->nsevent = nsevent;
+  [info->nsevent retain];
+
   info->source_widget = g_object_ref (widget);
   info->widget = g_object_ref (widget);
   info->target_list = target_list;
@@ -1160,10 +1200,6 @@ gtk_drag_begin_internal (GtkWidget         *widget,
          }
     }
 
-  nswindow = get_toplevel_nswindow (widget);
-  info->nsevent = [nswindow currentEvent];
-  [info->nsevent retain];
-
   /* drag will begin in an idle handler to avoid nested run loops */
 
   g_idle_add_full (G_PRIORITY_HIGH_IDLE, gtk_drag_begin_idle, context, NULL);
@@ -1802,7 +1838,7 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
   pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard];
   [pasteboard declareTypes: nil owner: nil];
 
-  [pool relase];
+  [pool release];
 
   gtk_drag_clear_source_info (info->context);
   g_object_unref (info->context);